package com.farsunset.ichat.cim.handler;

import static org.jboss.netty.channel.Channels.pipeline;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;

import com.farsunset.cim.nio.constant.CIMConstant;
import com.farsunset.cim.nio.filter.ServerMessageDecoder;
import com.farsunset.cim.nio.filter.ServerMessageEncoder;
import com.farsunset.cim.nio.handler.CIMRequestHandler;
import com.farsunset.cim.nio.mutual.ReplyBody;
import com.farsunset.cim.nio.mutual.SentBody;
import com.farsunset.cim.nio.session.CIMSession;
import com.farsunset.cim.nio.session.SessionManager;
import com.farsunset.ichat.common.util.ContextHolder;

public class MainIOHandler extends SimpleChannelUpstreamHandler {

	protected final Logger logger = Logger.getLogger(MainIOHandler.class);

	private HashMap<String, CIMRequestHandler> handlers = new HashMap<String, CIMRequestHandler>();

	private int port;
	
	public void init()	{
		ServerBootstrap bootstrap = new ServerBootstrap(  
                new NioServerSocketChannelFactory(  
                        Executors.newCachedThreadPool(),  
                        Executors.newCachedThreadPool()));  
		
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {     	
  
            @Override  
            public ChannelPipeline getPipeline() throws Exception {              	
            	ChannelPipeline pipeline = pipeline();
            	pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, new ChannelBuffer[] {
    	                ChannelBuffers.wrappedBuffer(new byte[] { CIMConstant.MESSAGE_SEPARATE }) }));
            	pipeline.addLast("decoder", new ServerMessageDecoder());
            	pipeline.addLast("encoder", new ServerMessageEncoder());
            	pipeline.addLast("handler", MainIOHandler.this);            	
            	return pipeline;
            }    
        });  
        bootstrap.setOption("tcpNoDelay" , true);  
        bootstrap.setOption("tcpNoDelay" , 0);  
        bootstrap.setOption("tcpNoDelays" , true);          
        bootstrap.setOption("keepAlive", true);  
        bootstrap.bind(new InetSocketAddress(port));  
        logger.warn("netty 启动成功" + port);
	}	
	 
	public void  channelConnected(ChannelHandlerContext ctx, ChannelStateEvent event)	{		
		logger.warn("sessionCreated()... from "+ctx.getChannel().getRemoteAddress().toString());
	}	 
	
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)  
			throws Exception {
		logger.debug("message: " + e.getMessage().toString());		
		
		/**
		 * flex 客户端安全策略请求，需要返回特定报文
		 */
		if(CIMConstant.FLEX_POLICY_REQUEST.equals(e.getMessage())) {
			ctx.getChannel().write(CIMConstant.FLEX_POLICY_RESPONSE);
			return ;
		}
		
		CIMSession cimSession =new  CIMSession(ctx.getChannel());
		ReplyBody reply = new ReplyBody();
		SentBody body = (SentBody) e.getMessage();
		String key = body.getKey();

		CIMRequestHandler handler = handlers.get(key);
		if (handler == null) {
			reply.setCode(CIMConstant.ReturnCode.CODE_405);
			reply.setMessage("KEY ["+key+"] 服务端未定义");
		} else {
			reply = handler.process(cimSession, body);
		}
		
        if(reply!=null) {
        	reply.setKey(key);
        	cimSession.write(reply);
    		logger.debug("-----------------------process done. reply: " + reply.toString());
        }
        
        //设置心跳时间 
        cimSession.setAttribute(CIMConstant.HEARTBEAT_KEY, System.currentTimeMillis());
	}

	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent event) {
		String account = "";
		try{
			CIMSession cimSession =new  CIMSession(ctx.getChannel());
			account = cimSession.getAttribute(CIMConstant.SESSION_KEY).toString();   	
			logger.warn("sessionClosed()... from "+cimSession.getRemoteAddress());
			CIMRequestHandler handler = handlers.get("sessionClosedHander");
			if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY)) {
				handler.process(cimSession, null);
			}
		}catch(Exception e) {	
			SessionManager sessionManager = ContextHolder.getBean(SessionManager.class);
			sessionManager.removeSession(account);
		}
	}
	 
	 
	/**
	 *//*
	 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent event) {
		CIMSession cimSession =new  CIMSession(ctx.getChannel());
		try{
			logger.warn("sessionClosed()... from "+cimSession.getRemoteAddress());
			CIMRequestHandler handler = handlers.get("sessionClosedHander");
			if(handler!=null && cimSession.containsAttribute(CIMConstant.SESSION_KEY))
			{
				handler.process(cimSession, null);
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}*/

	public void setHandlers(HashMap<String, CIMRequestHandler> handlers) {
		this.handlers = handlers;
	}

	public void setPort(int port) {
		this.port = port;
	}
}